使用预训练的词向量完成文本分类任务

您所在的位置:网站首页 飞桨 java 使用预训练的词向量完成文本分类任务

使用预训练的词向量完成文本分类任务

2023-11-11 23:38| 来源: 网络整理| 查看: 265

二、数据载入¶

在这个示例中,将使用 Paddle 2.3.0 完成针对 Imdb 数据集(电影评论情感二分类数据集)的分类训练和测试。Imdb 将直接调用自 Paddle 2.3.0,同时, 利用预训练的词向量(GloVe embedding)完成任务。

print('自然语言相关数据集:', paddle.text.__all__) 自然语言相关数据集: ['Conll05st', 'Imdb', 'Imikolov', 'Movielens', 'UCIHousing', 'WMT14', 'WMT16', 'ViterbiDecoder', 'viterbi_decode']

由于 Paddle 2.3 提供了经过处理的Imdb数据集,可以方便地调用所需要的数据实例,省去了数据预处理的麻烦。目前, Paddle 2.3 以及内置的高质量 数据集包括 Conll05st、Imdb、Imikolov、Movielens、HCIHousing、WMT14、WMT16、ViterbiDecoder、viterbi_decode 等,未来还将提供更多常用数据集的调用接口。

以下定义了调用 Imdb 训练集合测试集的方法。其中,cutoff 定义了构建词典的截止大小,即数据集中出现频率在 cutoff 以下的不予考虑;mode 定义了返回的数据用于何种用途(test: 测试集,train: 训练集)。

2.1 定义数据集¶ imdb_train = text.Imdb(mode='train', cutoff=150) imdb_test = text.Imdb(mode='test', cutoff=150)

调用 Imdb 得到的是经过编码的数据集,每个 term 对应一个唯一 id,映射关系可以通过 imdb_train.word_idx 查看。将每一个样本即一条电影评论,表示成 id 序列。可以检查一下以上生成的数据内容:

print("训练集样本数量: %d; 测试集样本数量: %d" % (len(imdb_train), len(imdb_test))) print(f"样本标签: {set(imdb_train.labels)}") print(f"样本字典: {list(imdb_train.word_idx.items())[:10]}") print(f"单个样本: {imdb_train.docs[0]}") print(f"最小样本长度: {min([len(x) for x in imdb_train.docs])};最大样本长度: {max([len(x) for x in imdb_train.docs])}") 训练集样本数量: 25000; 测试集样本数量: 25000 样本标签: {0, 1} 样本字典: [(b'the', 0), (b'and', 1), (b'a', 2), (b'of', 3), (b'to', 4), (b'is', 5), (b'in', 6), (b'it', 7), (b'i', 8), (b'this', 9)] 单个样本: [5146, 43, 71, 6, 1092, 14, 0, 878, 130, 151, 5146, 18, 281, 747, 0, 5146, 3, 5146, 2165, 37, 5146, 46, 5, 71, 4089, 377, 162, 46, 5, 32, 1287, 300, 35, 203, 2136, 565, 14, 2, 253, 26, 146, 61, 372, 1, 615, 5146, 5, 30, 0, 50, 3290, 6, 2148, 14, 0, 5146, 11, 17, 451, 24, 4, 127, 10, 0, 878, 130, 43, 2, 50, 5146, 751, 5146, 5, 2, 221, 3727, 6, 9, 1167, 373, 9, 5, 5146, 7, 5, 1343, 13, 2, 5146, 1, 250, 7, 98, 4270, 56, 2316, 0, 928, 11, 11, 9, 16, 5, 5146, 5146, 6, 50, 69, 27, 280, 27, 108, 1045, 0, 2633, 4177, 3180, 17, 1675, 1, 2571] 最小样本长度: 10;最大样本长度: 2469

对于训练集,将数据的顺序打乱,以优化将要进行的分类模型训练的效果。

shuffle_index = list(range(len(imdb_train))) random.shuffle(shuffle_index) train_x = [imdb_train.docs[i] for i in shuffle_index] train_y = [imdb_train.labels[i] for i in shuffle_index] test_x = imdb_test.docs test_y = imdb_test.labels

从样本长度上可以看到,每个样本的长度是不相同的。然而,在模型的训练过程中,需要保证每个样本的长度相同,以便于构造矩阵进行批量运算。 因此,需要先对所有样本进行填充或截断,使样本的长度一致。

def vectorizer(input, label=None, length=2000): if label is not None: for x, y in zip(input, label): yield np.array((x + [0]*length)[:length]).astype('int64'), np.array([y]).astype('int64') else: for x in input: yield np.array((x + [0]*length)[:length]).astype('int64') 2.2 载入预训练向量¶

以下给出的文件较小,可以直接完全载入内存。对于大型的预训练向量,无法一次载入内存的,可以采用分批载入,并行处理的方式进行匹配。 此外,AIStudio 中提供了 glove.6B 数据集挂载,用户可在 AIStudio 中直接载入数据集并解压。

# 下载并解压预训练向量 !wget http://nlp.stanford.edu/data/glove.6B.zip !unzip -q glove.6B.zip glove_path = "./glove.6B.100d.txt" embeddings = {}

观察上述GloVe预训练向量文件一行的数据:

# 使用utf8编码解码 with open(glove_path, encoding='utf-8') as gf: line = gf.readline() print("GloVe单行数据:'%s'" % line) GloVe单行数据:'the -0.038194 -0.24487 0.72812 -0.39961 0.083172 0.043953 -0.39141 0.3344 -0.57545 0.087459 0.28787 -0.06731 0.30906 -0.26384 -0.13231 -0.20757 0.33395 -0.33848 -0.31743 -0.48336 0.1464 -0.37304 0.34577 0.052041 0.44946 -0.46971 0.02628 -0.54155 -0.15518 -0.14107 -0.039722 0.28277 0.14393 0.23464 -0.31021 0.086173 0.20397 0.52624 0.17164 -0.082378 -0.71787 -0.41531 0.20335 -0.12763 0.41367 0.55187 0.57908 -0.33477 -0.36559 -0.54857 -0.062892 0.26584 0.30205 0.99775 -0.80481 -3.0243 0.01254 -0.36942 2.2167 0.72201 -0.24978 0.92136 0.034514 0.46745 1.1079 -0.19358 -0.074575 0.23353 -0.052062 -0.22044 0.057162 -0.15806 -0.30798 -0.41625 0.37972 0.15006 -0.53212 -0.2055 -1.2526 0.071624 0.70565 0.49744 -0.42063 0.26148 -1.538 -0.30223 -0.073438 -0.28312 0.37104 -0.25217 0.016215 -0.017099 -0.38984 0.87424 -0.72569 -0.51058 -0.52028 -0.1459 0.8278 0.27062 '

可以看到,每一行都以单词开头,其后接上该单词的向量值,各个值之间用空格隔开。基于此,可以用如下方法得到所有词向量的字典。

with open(glove_path, encoding='utf-8') as gf: for glove in gf: word, embedding = glove.split(maxsplit=1) embedding = [float(s) for s in embedding.split(' ')] embeddings[word] = embedding print("预训练词向量总数:%d" % len(embeddings)) print(f"单词'the'的向量是:{embeddings['the']}") 预训练词向量总数:400000 单词'the'的向量是:[-0.038194, -0.24487, 0.72812, -0.39961, 0.083172, 0.043953, -0.39141, 0.3344, -0.57545, 0.087459, 0.28787, -0.06731, 0.30906, -0.26384, -0.13231, -0.20757, 0.33395, -0.33848, -0.31743, -0.48336, 0.1464, -0.37304, 0.34577, 0.052041, 0.44946, -0.46971, 0.02628, -0.54155, -0.15518, -0.14107, -0.039722, 0.28277, 0.14393, 0.23464, -0.31021, 0.086173, 0.20397, 0.52624, 0.17164, -0.082378, -0.71787, -0.41531, 0.20335, -0.12763, 0.41367, 0.55187, 0.57908, -0.33477, -0.36559, -0.54857, -0.062892, 0.26584, 0.30205, 0.99775, -0.80481, -3.0243, 0.01254, -0.36942, 2.2167, 0.72201, -0.24978, 0.92136, 0.034514, 0.46745, 1.1079, -0.19358, -0.074575, 0.23353, -0.052062, -0.22044, 0.057162, -0.15806, -0.30798, -0.41625, 0.37972, 0.15006, -0.53212, -0.2055, -1.2526, 0.071624, 0.70565, 0.49744, -0.42063, 0.26148, -1.538, -0.30223, -0.073438, -0.28312, 0.37104, -0.25217, 0.016215, -0.017099, -0.38984, 0.87424, -0.72569, -0.51058, -0.52028, -0.1459, 0.8278, 0.27062] 3.3 给数据集的词表匹配词向量¶

接下来,提取数据集的词表,需要注意的是,词表中的词编码的先后顺序是按照词出现的频率排列的,频率越高的词编码值越小。

word_idx = imdb_train.word_idx vocab = [w for w in word_idx.keys()] print(f"词表的前5个单词:{vocab[:5]}") print(f"词表的后5个单词:{vocab[-5:]}") 词表的前5个单词:[b'the', b'and', b'a', b'of', b'to'] 词表的后5个单词:[b'troubles', b'virtual', b'warriors', b'widely', '']

观察词表的后5个单词,发现最后一个词是””,这个符号代表所有词表以外的词。另外,对于形式b’the’,是字符串’the’ 的二进制编码形式,使用中注意使用b’the’.decode()来进行转换(’’并没有进行二进制编码,注意区分)。 接下来,给词表中的每个词匹配对应的词向量。预训练词向量可能没有覆盖数据集词表中的所有词,对于没有的词,设该词的词 向量为零向量。

# 定义词向量的维度,注意与预训练词向量保持一致 dim = 100 vocab_embeddings = np.zeros((len(vocab), dim)) for ind, word in enumerate(vocab): if word != '': word = word.decode() embedding = embeddings.get(word, np.zeros((dim,))) vocab_embeddings[ind, :] = embedding


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3